package com.solidumgame.martillo.nail
{
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.Joints.b2RevoluteJoint;
	import Box2D.Dynamics.Joints.b2RevoluteJointDef;
	import Box2D.Dynamics.b2Body;
	
	import com.greensock.TweenMax;
	import com.greensock.easing.Linear;
	import com.pblabs.box2D.CollisionEvent;
	import com.pblabs.engine.PBE;
	import com.pblabs.engine.components.AnimatedComponent;
	import com.pblabs.engine.core.ObjectType;
	import com.pblabs.engine.debug.Logger;
	import com.solidumgame.martillo.hammer.Hammer;
	import com.solidumgame.martillo.nail.events.NailGenericEvent;
	import com.solidumgame.martillo.tablewood.TableWood;
	import com.solidumgame.martillo.tablewood.TableWoodSpatialComponent;
	import com.solidumgame.martillo.utils.RandomGenerator;
	
	import flash.geom.Point;
	
	/**
	 *  
	 * @author Tdadone
	 * 
	 */	
	public class NailLogicComponent extends AnimatedComponent
	{

		private var tries:int;
		private var forceToBalance:Number;
		private var forceToFall:Number;
		private var jointArray:Array;
		private var nailSize:int;
		private var twSpatial:TableWoodSpatialComponent;
		private var spatialComp:NailSpatialComponent;
		
		private var angle:Number= -100;
		private var moveVec:b2Vec2;
		private var nailPosition:int = 0; 
		private var movePoint:Point = new Point();
		
		/**
		 * 
		 * @param size
		 * 
		 */		
		public function NailLogicComponent(size:int)
		{
			super();
			nailSize = size;
		}

		override protected function onReset():void{
			super.onReset();
			
			//No registramos eventos
			this.registerForUpdates = false;
			
			//Determina intentos antes de caerse
			tries = RandomGenerator.getRandom()*5+4;
			
			//Determina fuerza con la que se empuja al clavo
			if(nailSize==Nail.SIZE_LARGE){
				forceToBalance = 20;
				forceToFall = 18;
				nailPosition = 3;
			}else if(nailSize==Nail.SIZE_MEDIUM){
				forceToBalance = 18;
				forceToFall = 16;
				nailPosition = 2;
			}else{
				forceToBalance = 16;
				forceToFall = 4;
				nailPosition = 1;
			}
			
			//Nuevo arreglo de joints
			jointArray = new Array();
			
			//Componentes espaciales de Nail y Tablewood
			twSpatial = (TableWoodSpatialComponent)(PBE.lookupComponentByName("TableWood","Spatial"));
			spatialComp = (NailSpatialComponent)(owner.lookupComponentByName("Spatial"));		
		
			//Actualizamos el choque de Nail, solo con Tablewood
			spatialComp.body.updateFilter(new ObjectType(TableWood.TYPE).bits);
			
			//Esperamos que colisione con el piso
			owner.eventDispatcher.addEventListener(CollisionEvent.COLLISION_EVENT, floorCollision);	
		}
		
		protected function floorCollision(e:CollisionEvent):void{
			
			//Removemos listener
			owner.eventDispatcher.removeEventListener(CollisionEvent.COLLISION_EVENT, floorCollision);
			
			//Sonido Nail contra tabla
			owner.eventDispatcher.dispatchEvent(new NailGenericEvent(NailGenericEvent.NAIL_FLOOR_HIT_EVENT));
			
			//Atachamos el Nail al piso
			fixNailToFloor();		
			
			
		}
		
		protected function fixNailToFloor():void{
			this.registerForUpdates = false;
			
			Logger.debug(this,"fixNailToFloor",owner.name+" Clavado al piso");
			
			//Removemos joints anteriores
			removeJoints();
			
			//Seteamos el angulo en 0
			spatialComp.body.SetXForm(spatialComp.body.GetPosition(),0);
			angle = -100;
			
			//Atachamos parte izquierda
			var position:b2Vec2 = spatialComp.getLeftBasePoint();
			position.y = twSpatial.getFloorLimit();
			
			var jointDef:b2RevoluteJointDef = new b2RevoluteJointDef();
			jointDef.Initialize(spatialComp.body, twSpatial.body, position);
			var joint:b2RevoluteJoint = (b2RevoluteJoint)(spatialComp.body.GetWorld().CreateJoint(jointDef));
			jointArray.push(joint);
			
			//Atachamos parte derecha
			position.x = spatialComp.getRightBasePoint().x;
			jointDef = new b2RevoluteJointDef();
			jointDef.Initialize(spatialComp.body, twSpatial.body, position);
			joint = (b2RevoluteJoint)(spatialComp.body.GetWorld().CreateJoint(jointDef));
			jointArray.push(joint);
			
			//Actualizamos el choque de Nail, colisione con todo
			spatialComp.body.updateFilter(new ObjectType(TableWood.TYPE,Hammer.TYPE).bits);
			
			balanceAndFall();
			
			owner.eventDispatcher.addEventListener(CollisionEvent.COLLISION_EVENT, hammerCollision);
		}	
				
		protected function balanceAndFall():void{
			if(owner){
				if(tries>=0){				
					//Empujamos el Nail para que se balancee
					spatialComp.body.ApplyTorque(forceToBalance);
					tries--;
					TweenMax.delayedCall(2,balanceAndFall);
				}else{	
					Logger.debug(this,"balanceAndFall",owner.name+" Debe caerse");
					
					//Removemos listener
					owner.eventDispatcher.removeEventListener(CollisionEvent.COLLISION_EVENT, hammerCollision);
					
					//El Nail debe caerse
					spatialComp.body.updateFilter(new ObjectType(TableWood.TYPE).bits);
					removeJoints();
					TweenMax.killTweensOf(moveVec);
					spatialComp.body.ApplyTorque(forceToFall);
					
					//Llamamos a que se caiga el Nail
					nailFallen();
				}
			}
		}
		
		protected function nailFallen():void{
			if(owner){
				if(!spatialComp.body.IsSleeping())
					TweenMax.delayedCall(1,nailFallen);
				else{
					
					Logger.debug(this,"nailFallen",owner.name+" Caido");
					
					
					var fixPoint:b2Vec2 = new b2Vec2(spatialComp.body.GetPosition().x , spatialComp.body.GetPosition().y);
					var jointDef:b2RevoluteJointDef = new b2RevoluteJointDef();
					jointDef.Initialize( spatialComp.body, twSpatial.body, fixPoint);
					var joint:b2RevoluteJoint = (b2RevoluteJoint)(spatialComp.body.GetWorld().CreateJoint(jointDef));
					jointArray.push(joint);
					
					var otherFixPoint:b2Vec2 = new b2Vec2(spatialComp.body.GetPosition().x + 0.1, spatialComp.body.GetPosition().y);
					jointDef.Initialize( spatialComp.body, twSpatial.body, otherFixPoint);
					joint = (b2RevoluteJoint)(spatialComp.body.GetWorld().CreateJoint(jointDef));
					jointArray.push(joint);
					
					
					spatialComp.body.m_flags |= b2Body.e_frozenFlag;
					spatialComp.body.PutToSleep();
					
					owner.eventDispatcher.dispatchEvent(new NailGenericEvent(NailGenericEvent.NAIL_NOT_NAILED_EVENT));
					PBE.mainStage.dispatchEvent(new NailGenericEvent(NailGenericEvent.NAIL_NOT_NAILED_EVENT));
				}
			}
		}		
		
		protected function hammerCollision(e:CollisionEvent):void{
			
			if(e.collider.collisionType.bits == new ObjectType(Hammer.TYPE).bits){
				
				//Removemos listener
				owner.eventDispatcher.removeEventListener(CollisionEvent.COLLISION_EVENT, hammerCollision);
				
				Logger.debug(this,"hammerCollision",owner.name+" Colisiono con Hammer");
				TweenMax.killDelayedCallsTo(balanceAndFall);
				spatialComp.body.updateFilter(new ObjectType(Hammer.TYPE).bits);
				removeJoints();
				moveDown();			
				
			}
		}	
		
		
		protected function moveDown():void{
			Logger.debug(this,"moveDown",owner.name+" Moviendose para abajo");
			
			//Si el angulo de clavado no esta seteado
			if(angle==-100)
				angle = spatialComp.body.GetAngle();
			
		
			if(nailPosition){
				
				//Determinamos posicion de bajada
				var positionX:Number = spatialComp.position.x;
				var positionY:Number;
				
				if(nailPosition==1){
					positionY = twSpatial.upperLimit + spatialComp.ratioY - 3;
				}else if(nailPosition==2){
					positionY = twSpatial.upperLimit + spatialComp.ratioY - 26 - 3 ;
				}else if(nailPosition==3){
					positionY = twSpatial.upperLimit + spatialComp.ratioY - 44 - 3;
				}
				
				//Calculamos el punto de bajada
				var fixPoint:b2Vec2 = new b2Vec2(positionX,positionY);
				fixPoint.Multiply(spatialComp.spatialManager.inverseScale);
				
				moveVec =  new b2Vec2(spatialComp.body.GetPosition().x,spatialComp.body.GetPosition().y);
				
				var to:Number = fixPoint.y;
				
				TweenMax.killTweensOf(moveVec);
				TweenMax.to(moveVec,0.4,{y:to, ease:Linear.easeNone, onComplete:fixNail,onCompleteParams:[fixPoint]});

				this.registerForUpdates = true;
			}
			
			
			
		}
		
		protected function fixNail(fixPoint:b2Vec2):void{
			
			Logger.debug(this,"fixNail",owner.name+" Fijando en un punto");
			//Bajamos una posicion		
			nailPosition--;
			
			if(nailPosition<=0){
				
				if(owner)
					owner.eventDispatcher.removeEventListener(CollisionEvent.COLLISION_EVENT, hammerCollision);
				
				Logger.debug(this,"fixNail",owner.name+" Clavo clavado");
				
				this.registerForUpdates = false;
				
				//Sacamos los movimientos y joints
				removeJoints();
				TweenMax.killTweensOf(moveVec);
				TweenMax.killDelayedCallsTo(liftedUp);
				
				//Fijamos bien la posicion
				spatialComp.body.SetXForm(moveVec,angle);
				
				var upperPoint:b2Vec2 = new b2Vec2(moveVec.x,moveVec.y-0.15);
				
				var upperJointDef:b2RevoluteJointDef = new b2RevoluteJointDef();
				upperJointDef.Initialize( spatialComp.body, twSpatial.body, upperPoint);
				var upperJoint:b2RevoluteJoint = (b2RevoluteJoint)(spatialComp.body.GetWorld().CreateJoint(upperJointDef));
				jointArray.push(upperPoint);
				
				var lowerPoint:b2Vec2 = new b2Vec2(moveVec.x,moveVec.y+0.15);
				
				var lowerJointDef:b2RevoluteJointDef = new b2RevoluteJointDef();
				lowerJointDef.Initialize( spatialComp.body, twSpatial.body, lowerPoint);
				var lowerJoint:b2RevoluteJoint = (b2RevoluteJoint)(spatialComp.body.GetWorld().CreateJoint(lowerJointDef));
				jointArray.push(lowerJoint);
				
				
				moveVec = new b2Vec2(fixPoint.x,fixPoint.y);
				spatialComp.body.SetXForm(moveVec,spatialComp.body.GetAngle());
				
				this.registerForUpdates = false;
				spatialComp.body.m_flags |= b2Body.e_frozenFlag;
				
				
				
				if(owner)
					owner.eventDispatcher.dispatchEvent(new NailGenericEvent(NailGenericEvent.NAIL_NAILED_EVENT));
				PBE.mainStage.dispatchEvent(new NailGenericEvent(NailGenericEvent.NAIL_NAILED_EVENT));
				
			}else{
				
				liftNail();
				if(owner)
					owner.eventDispatcher.addEventListener(CollisionEvent.COLLISION_EVENT, hammerCollision);
			}
			
			
			
		}

		protected function liftNail():void{

			
			if(owner){
				Logger.debug(this,"liftNail",owner.name+" Subiendo");
				if(nailSize!=Nail.SIZE_SMALL){
					var positionY:Number;
					if(nailSize==Nail.SIZE_LARGE){
						if(nailPosition==1){
							positionY = twSpatial.upperLimit + spatialComp.ratioY - 44 - 3;
						}else if(nailPosition==2){
							positionY = twSpatial.upperLimit + spatialComp.ratioY - 62 - 3;
						}
					}else if(nailSize==Nail.SIZE_MEDIUM){
						if(nailPosition==1){
							positionY = twSpatial.upperLimit + spatialComp.ratioY - 44 - 3;
						}
					}
					
					var fixPoint:b2Vec2 = new b2Vec2(0,positionY);
					
					fixPoint.Multiply(spatialComp.spatialManager.inverseScale);
					var to:Number = fixPoint.y;
					moveVec =  new b2Vec2(spatialComp.body.GetPosition().x,spatialComp.body.GetPosition().y);
					
					var velocidadSubidad:Number = RandomGenerator.getRandom()*5+5;
					TweenMax.killTweensOf(moveVec);
					TweenMax.killDelayedCallsTo(liftedUp);
					TweenMax.to(moveVec,velocidadSubidad,{y:to, ease:Linear.easeNone});
					TweenMax.delayedCall(velocidadSubidad,liftedUp);
					
				}
			}
		
		}

		
		protected function liftedUp():void{
			
			if(owner){
				Logger.debug(this,"liftNail",owner.name+" Subido");
				nailPosition++;
				if(nailSize==Nail.SIZE_LARGE){
					if(nailPosition>=3){
						if(owner){
							owner.eventDispatcher.removeEventListener(CollisionEvent.COLLISION_EVENT, hammerCollision);
							this.registerForUpdates = false;
							fixNailToFloor();
						}
					}else if(nailPosition==2){
						liftNail();
					}
				}else if(nailSize==Nail.SIZE_MEDIUM){
					if(nailPosition==2){
						if(owner){
							owner.eventDispatcher.removeEventListener(CollisionEvent.COLLISION_EVENT, hammerCollision);
							this.registerForUpdates = false;
							fixNailToFloor();
						}
					}
				}
			}
		}
		
		protected function removeJoints():void{
			
			for each(var joint:b2RevoluteJoint in jointArray){
				spatialComp.body.GetWorld().DestroyJoint(joint);
			}
			
			var jointLength:int = jointArray.length;
			
			for (var i:int = 0; i < jointLength; i++) 
			{
				jointArray.pop();	
			}			
		}
		
		override public function onFrame(tickRate:Number):void{
			super.onFrame(tickRate);
			removeJoints();
			
			spatialComp.body.SetXForm(moveVec,angle);
			
			var upperPoint:b2Vec2 = new b2Vec2(moveVec.x,moveVec.y-0.15);
			
			var upperJointDef:b2RevoluteJointDef = new b2RevoluteJointDef();
			upperJointDef.Initialize( spatialComp.body, twSpatial.body, upperPoint);
			var upperJoint:b2RevoluteJoint = (b2RevoluteJoint)(spatialComp.body.GetWorld().CreateJoint(upperJointDef));
			jointArray.push(upperJoint);
			
			var lowerPoint:b2Vec2 = new b2Vec2(moveVec.x,moveVec.y+0.15);
			var lowerJointDef:b2RevoluteJointDef = new b2RevoluteJointDef();
			lowerJointDef.Initialize( spatialComp.body, twSpatial.body, lowerPoint);
			var lowerJoint:b2RevoluteJoint = (b2RevoluteJoint)(spatialComp.body.GetWorld().CreateJoint(lowerJointDef));
			jointArray.push(lowerJoint);
		}

		
		override protected function onRemove():void{
			super.onRemove();
			
			TweenMax.killTweensOf(moveVec);
			TweenMax.killDelayedCallsTo(liftedUp);
			
			spatialComp = null;
			twSpatial = null;
			
			moveVec = null;
			movePoint = null; 			
		}

	}
}